﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HBCode.BusinessLogic.Entities;
using HBCode.Presentation.Base;
using System.Collections.ObjectModel;
using System.Windows.Input;
using HBCode.Presentation.Command;
using System.Windows;

namespace HBCode.Presentation
{
    public class CustomerViewModel : ViewModelBase
    {
        #region Properties

        private ObservableCollection<Customer> _Customers;
        public ObservableCollection<Customer> Customers
        {
            get
            {
                return _Customers = _Customers ?? new ObservableCollection<Customer>(DbManager.Customers);
            }
            set
            {
                if (_Customers == value)
                    return;
                OnPropertyChanging("Customers");
                _Customers = value;
                OnPropertyChanged("Customers");
            }
        }

        private Customer _underLyingCustomer;
        private Customer _activeCustomer;
        public Customer ActiveCustomer
        {
            get { return _activeCustomer; }
            set
            {
                OnPropertyChanging("ActiveCustomer");
                if (value != null)
                {
                    value.IsDirty = false;
                    _underLyingCustomer = value;
                    _activeCustomer = value.Clone<Customer>();
                }
                else
                {
                    _activeCustomer = null;
                    _underLyingCustomer = null;
                }
                IsEditing = value != null;
                OnPropertyChanged("ActiveCustomer");
            }
        }

        #endregion

        #region Commandings

        private ICommand _viewCommand;
        /// <summary>
        /// View Command for customer
        /// </summary>
        public ICommand ViewCommand
        {
            get
            {
                _viewCommand = _viewCommand = new DelegateCommand<Customer>((param) =>
                {
                    ActiveCustomer = param;
                    this.Parent.ActiveChildViewModel = this;
                }, new Func<Customer, bool>(ValidateView));
                return _viewCommand;
            }
        }

        private ICommand _addNewCommand;
        /// <summary>
        /// Add Command for customer
        /// </summary>
        public ICommand AddNewCommand
        {
            get
            {
                _addNewCommand = _addNewCommand = new DelegateCommand(() =>
                {
                    Customer newCustomer = new Customer();
                    newCustomer.IsExists = false;

                    ActiveCustomer = newCustomer;
                    this.Parent.ActiveChildViewModel = this;
                }, new Func<bool>(ValidateAdd));
                return _addNewCommand;
            }
        }

        private ICommand _cancelCommand;
        /// <summary>
        /// Cancel Command for active customer
        /// </summary>
        public ICommand CancelCommand
        {
            get
            {
                _cancelCommand = _cancelCommand = new DelegateCommand(() =>
                {
                    ActiveCustomer = null;
                }, new Func<bool>(ValidateCancel));
                return _cancelCommand;
            }
        }

        private ICommand _deleteCommand;
        /// <summary>
        /// Delete Command for customer
        /// </summary>
        public ICommand DeleteCommand
        {
            get
            {
                _deleteCommand = _deleteCommand = new DelegateCommand(() =>
                {
                    try
                    {
                        if (ShowMessageDialog("Confirm Delete", "Are you sure to delete the record ?", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
                        {
                            Customer delCustomer = DbManager.Customers.Find(ActiveCustomer.CustomerID);
                            if (delCustomer != null)
                            {
                                DbManager.Customers.Remove(delCustomer);
                                DbManager.SaveChanges();
                                Customers.Remove(_underLyingCustomer);
                                ActiveCustomer = null;
                                ShowMessage("Deleted successfully", "Record deleted successfully", MessageBoxImage.Information);
                            }
                            else
                                ShowMessage("Delete failed", "Record not found to be deleted", MessageBoxImage.Error);
                        }
                    }
                    catch (InvalidOperationException)
                    {
                        ShowMessage("Delete failed", "Failed to delete the record", MessageBoxImage.Error);
                    }
                    catch (Exception ex)
                    {
                        ShowMessage("Unknown Error", string.Format("Error Details: {0}", ex.Message), MessageBoxImage.Error);
                    }
                }, new Func<bool>(ValidateDelete));
                return _deleteCommand;
            }
        }

        private ICommand _saveCommand;
        /// <summary>
        /// Save Command for customer
        /// </summary>
        public ICommand SaveCommand
        {
            get
            {
                _saveCommand = _saveCommand = new DelegateCommand(() =>
                {
                    try
                    {
                        if (ShowMessageDialog("Confirm Save", "Are you sure to save the record ?", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
                        {
                            if (!ActiveCustomer.IsExists)
                            {
                                DbManager.Customers.Add(ActiveCustomer);
                                DbManager.SaveChanges();
                                Customers.Add(ActiveCustomer);
                                ActiveCustomer.IsExists = true;
                                ActiveCustomer = null;
                            }
                            else
                            {
                                /* http://stackoverflow.com/a/6036662
                                 * If you load the entity from the context you cannot attach an entity with the same key again.
                                 * The first entity is still kept in internal context cache and
                                 * context can hold only one instance with given key value per type */

                                DbManager.Entry(_underLyingCustomer).CurrentValues.SetValues(ActiveCustomer);
                                DbManager.SaveChanges();
                            }

                            ShowMessage("Saved successfully", "Record saved successfully", MessageBoxImage.Information);
                        }
                    }
                    catch (InvalidOperationException)
                    {
                        ShowMessage("Save failed", "Failed to save the record", MessageBoxImage.Error);
                    }
                    catch (Exception ex)
                    {
                        ShowMessage("Unknown Error", string.Format("Error Details: {0}", ex.Message), MessageBoxImage.Error);
                    }
                }, new Func<bool>(ValidateSave));
                return _saveCommand;
            }
        }
        #endregion

        #region Validation

        public bool ValidateView(Customer customer)
        {
            return customer != null;
        }

        public bool ValidateAdd()
        {
            return ActiveCustomer == null;
        }

        public bool ValidateDelete()
        {
            return ActiveCustomer != null && ActiveCustomer.IsExists;
        }

        public bool ValidateSave()
        {
            return ActiveCustomer != null && ActiveCustomer.IsValid;
        }

        public bool ValidateCancel()
        {
            return ActiveCustomer != null;
        }

        #endregion

    }
}
